// $codepro.audit.disable com.instantiations.assist.eclipse.analysis.deserializeabilitySecurity
package org.mysofts.eclipseman;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.mysofts.eclipseman.util.AppLog;
import org.mysofts.eclipseman.util.MessageProvider;

/**
 * Classe qui représente une installation d'eclipse présente sur le disque.
 * 
 * @author reda
 * 
 */
public final class Eclipse { // $codepro.audit.disable
								// declareDefaultConstructors
	/**
	 * Pattern regex qui permet de trouver le numéro de version dans le fichier
	 * readme d'eclipse.
	 */
	private static final String ECLIPSE_RELEASE_REGEX = ".*Release\\s*([\\d\\.]+).*";
	/**
	 * Chemin relatif du fichier readme d'eclipse.
	 */
	private static final String ECLIPSE_README_PATH = "readme/readme_eclipse.html";
	/**
	 * Chemin relatif de l'executable d'eclipse.
	 */
	private static final String ECLIPSE_EXECUTABLE_PATH = "eclipse";
	/**
	 * Chaine renvoyée par {@link Eclipse#getReleaseVersion()} en cas d'echec de
	 * récupération de version.
	 */
	public static final String UNKOWN_VERSION = "Unkown";

	/**
	 * Répertoire d'installation de l'eclipse.
	 */
	private final File directory;
	/**
	 * Chemin de l'executable eclipse.
	 */
	private final File executable;
	/**
	 * Nom de l'installation d'eclipse.
	 */
	private final String name;

	/**
	 * Constructeur.
	 * 
	 * @param pDirectory
	 *            Repertoire d'installation de l'eclipse.
	 */
	public Eclipse(final File pDirectory) {
		this.directory = pDirectory;
		this.executable = new File(this.directory, ECLIPSE_EXECUTABLE_PATH);
		this.name = this.directory.getName();
	}

	/**
	 * Indique si l'objet représente une installation valide d'eclipse.
	 * 
	 * @return {@code true} si l'installation est valide.
	 */
	public boolean isValidInstallation() {
		return isValidEclipseInstallation(this.directory);
	}

	/**
	 * Retourne le nom de l'installation d'eclipse.
	 * 
	 * @return Nom de l'installation d'eclipse.
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * Récupère le numéro de version de cette installation d'eclipse.
	 * 
	 * @return Numéro de version de l'instalation d'eclipse, ou
	 *         {@link #UNKOWN_VERSION} en cas d'echec.
	 */
	// $codepro.audit.disable blockDepth
	public String getReleaseVersion() {
		final File aboutFile = new File(this.directory, ECLIPSE_README_PATH);
		try {
			AppLog.debug(MessageFormat.format(
					MessageProvider.get("logs").sub("eclipse")
							.sub("start-get-release").value(),
					aboutFile.getAbsolutePath(), this.name));
			final FileInputStream in = new FileInputStream(aboutFile);
			try {
				final List<String> lines = IOUtils.readLines(in);
				final Pattern regex = Pattern.compile(ECLIPSE_RELEASE_REGEX);
				for (String line : lines) {
					Matcher matcher = regex.matcher(line);
					if (matcher.find()) {
						String version = matcher.group(1).trim();
						return version;
					} // end if
				}
			} finally {
				in.close();
			}
			AppLog.debug(MessageFormat.format(
					MessageProvider.get("logs").sub("eclipse")
							.sub("end-get-release").value(),
					aboutFile.getAbsolutePath(), this.name));
		} catch (IOException ex) {
			AppLog.error(MessageFormat.format(
					MessageProvider.get("logs").sub("eclipse")
							.sub("error-get-release").value(),
					aboutFile.getAbsolutePath()), ex);
		}

		return UNKOWN_VERSION;
	}

	/**
	 * Dossier de l'eclipse.
	 * 
	 * @return dossier de l'eclipse.
	 */
	public File getDirectory() {
		return this.directory;
	}

	/**
	 * Executable de l'eclipse.
	 * 
	 * @return Executable de l'eclipse.
	 */
	public File getExecutable() {
		return this.executable;
	}

	/**
	 * Execute l'eclipse référencé par cet instance.
	 * 
	 * @throws IOException
	 *             Erreur d'execution.
	 */
	public void execute() throws IOException {
		AppLog.debug(MessageFormat.format(
				MessageProvider.get("logs").sub("eclipse").sub("start-execute")
						.value(), this.executable.getAbsolutePath()));
		try {
			final ProcessBuilder pbld = new ProcessBuilder(
					this.executable.getCanonicalPath());
			pbld.directory(this.directory);
			pbld.start();
		} catch (IOException ex) {
			AppLog.error(MessageFormat.format(
					MessageProvider.get("logs").sub("eclipse")
							.sub("error-execute").value(),
					this.executable.getAbsolutePath()), ex);
			throw ex;
		}
	}

	/**
	 * Indique si un répertoire correspond à une installation valide d'eclipse.
	 * 
	 * @param directory
	 *            Répertoire à tester.
	 * @return {@code true} si l'installation est valide.
	 */
	public static boolean isValidEclipseInstallation(final File directory) {
		if ((directory != null) && directory.exists()
				&& directory.isDirectory()) {
			final File executable = new File(directory, ECLIPSE_EXECUTABLE_PATH);
			return executable.exists() && executable.isFile();
		} // end if

		return false;
	}

	@Override
	public String toString() {
		return "Eclipse [directory=" + this.directory + ", name=" + this.name + "]";
	}

}
